// ****************************************************************
// Copyright 2012, Stephan Burguchev
// e-mail: me@sburg.net
// ****************************************************************
// *
using System;
using System.Globalization;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Xml.Serialization;
using Version = Updater.Utils.Version;

namespace Updater.Common
{
    /// <summary>
    /// </summary>
    [XmlRoot("update-information")]
    public class UpdateInformation : IXmlSerializable
    {
        public UpdateInformation(
            string title,
            string description,
            Version minVersion,
            Version version,
            DateTime publicationDate,
            Uri location,
            int size,
            Type updateType,
            byte[] checksum,
            ChecksumType? checksumType)
        {
            if (title == null)
            {
                throw new ArgumentNullException("title");
            }

            if (description == null)
            {
                throw new ArgumentNullException("description");
            }

            if (version == null)
            {
                throw new ArgumentNullException("version");
            }

            if (location == null)
            {
                throw new ArgumentNullException("location");
            }

            if (updateType == null)
            {
                throw new ArgumentNullException("updateType");
            }

            this.Version = version;
            this.Title = title;
            this.Description = description;
            this.PublicationDate = publicationDate;
            this.MinVersion = minVersion;
            this.Location = location;
            this.Size = size;
            this.UpdateType = updateType;
            this.Checksum = checksum;
            this.ChecksumType = checksumType;
        }

        public UpdateInformation()
        {
            this.Description = "";
            this.PublicationDate = DateTime.MinValue;
            this.Title = "";
            this.Version = new Version();
        }

        /// <summary>
        /// </summary>
        public byte[] Checksum { get; private set; }

        public ChecksumType? ChecksumType { get; private set; }

        /// <summary>
        ///     A short patch notes describing changes in this update.
        /// </summary>
        public string Description { get; private set; }

        /// <summary>
        /// </summary>
        public Uri Location { get; private set; }

        /// <summary>
        ///     A version of the application the update should be applied to.
        /// </summary>
        public Version MinVersion { get; private set; }

        /// <summary>
        /// </summary>
        public DateTime PublicationDate { get; private set; }

        /// <summary>
        /// </summary>
        public int Size { get; private set; }

        /// <summary>
        ///     A title of patch notes describing changes in this update.
        /// </summary>
        public string Title { get; private set; }

        public Type UpdateType { get; private set; }

        /// <summary>
        ///     A final version of the application after this update.
        /// </summary>
        public Version Version { get; private set; }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            var e = (XElement)XNode.ReadFrom(reader);

            this.Version = Version.Parse(e.Attribute("version").Value);
            this.Description = e.Element("description").Value;
            this.Location = new Uri(e.Element("location").Value);
            this.PublicationDate = DateTime.Parse(e.Element("publication-date").Value, CultureInfo.InvariantCulture);
            this.Size = int.Parse(e.Element("size").Value);
            this.Title = e.Element("title").Value;
            string minVersion = e.Element("min-version").Value;
            this.MinVersion = minVersion != ""
                                  ? Version.Parse(minVersion)
                                  : null;
            string updateType = e.Element("update-type").Value;
            this.UpdateType = updateType != ""
                                  ? Type.GetType(updateType)
                                  : null;
            string checksum = e.Element("checksum").Value;
            this.Checksum = checksum != ""
                                ? Convert.FromBase64String(checksum)
                                : null;
            string checksumType = e.Element("checksum-type").Value;
            this.ChecksumType = checksumType != ""
                                    ? (ChecksumType?)Enum.Parse(typeof(ChecksumType), checksumType)
                                    : null;
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteAttributeString("version", this.Version.ToString());
            writer.WriteElementString("title", this.Title);
            writer.WriteElementString("description", this.Description);
            writer.WriteElementString("publication-date", this.PublicationDate.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("min-version", this.MinVersion != null ? this.MinVersion.ToString() : "");
            writer.WriteElementString("update-type", this.UpdateType != null ? this.UpdateType.AssemblyQualifiedName : "");
            writer.WriteElementString("location", this.Location != null ? this.Location.ToString() : "");
            writer.WriteElementString("size", this.Size.ToString(CultureInfo.InvariantCulture));
            writer.WriteElementString("checksum", this.Checksum != null ? Convert.ToBase64String(this.Checksum) : "");
            writer.WriteElementString(
                "checksum-type",
                this.ChecksumType.HasValue ? this.ChecksumType.Value.ToString() : "");
        }
    }
}
